package com;

import java.io.File;
import java.util.Date;

import com.moilioncircle.redis.replicator.Configuration;
import com.moilioncircle.redis.replicator.FileType;
import com.moilioncircle.redis.replicator.RedisReplicator;
import com.moilioncircle.redis.replicator.Replicator;
import com.moilioncircle.redis.replicator.rdb.datatype.ExpiredType;
import com.moilioncircle.redis.replicator.rdb.datatype.KeyValuePair;

public class RedisRDBParser {

    public static void main(String[] args) {
        String rdbPath = "dump.rdb"; // 替换为您的RDB文件路径
        try {
            parseRDB(rdbPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void parseRDB(String filePath) throws Exception {
        // 1. 创建配置
        Configuration config = Configuration.defaultSetting()
                .setVerbose(false);

        // 2. 创建Replicator实例
        try (Replicator replicator = new RedisReplicator(
                new File(filePath), 
                FileType.RDB, 
                config)) {

            // 3. 正确设置异常处理器（3.9.0版本写法）
            replicator.setExceptionHandler(new ExceptionHandler() {
                @Override
                public void handle(Exception e, Replicator replicator) {
                    System.err.println("处理RDB时出错: " + e.getMessage());
                    replicator.close();
                }
            });

            // 4. 添加RDB解析监听器
            replicator.addRdbListener(new RdbListener.Adaptor() {
                @Override
                public void handle(Replicator replicator, KeyValuePair<?> kv) {
                    printKeyValue(kv);
                }
            });

            // 5. 开始解析
            replicator.open();
        }
    }

    private static void printKeyValue(KeyValuePair<?> kv) {
        StringBuilder sb = new StringBuilder();
        
        // 数据库编号
        sb.append("DB").append(kv.getDb()).append(" | ");
        
        // 过期时间处理
        if (kv.getExpiredType() != ExpiredType.NONE) {
            long expireTime = kv.getExpiredValue();
            if (kv.getExpiredType() == ExpiredType.SEC) {
                expireTime *= 1000;
            }
            sb.append("Expire: ").append(new Date(expireTime)).append(" | ");
        }
        
        // 键
        sb.append("Key: ").append(byteToString(kv.getKey())).append(" | ");
        
        // 值和类型
        sb.append("Type: ").append(kv.getRdbType()).append(" | ");
        sb.append("Value: ").append(parseValue(kv.getValue(), kv.getRdbType()));
        
        System.out.println(sb.toString());
    }

    private static String byteToString(Object bytes) {
        if (bytes == null) return "null";
        if (bytes instanceof byte[]) return new String((byte[]) bytes);
        return bytes.toString();
    }

    private static String parseValue(Object value, RdbType type) {
        if (value == null) return "null";
        
        try {
            switch (type) {
                case STRING:
                    return byteToString(value);
                case LIST:
                    return formatList((List<?>) value);
                case SET:
                    return formatSet((Set<?>) value);
                case ZSET:
                    return formatZSet((ZSetEntry[]) value);
                case HASH:
                    return formatHash((Map<?, ?>) value);
                default:
                    return value.toString();
            }
        } catch (Exception e) {
            return "[Parse Error]";
        }
    }

    private static String formatList(List<?> list) {
        StringBuilder sb = new StringBuilder("[");
        list.forEach(item -> sb.append(byteToString(item)).append(", "));
        if (!list.isEmpty()) sb.setLength(sb.length() - 2);
        return sb.append("]").toString();
    }

    private static String formatSet(Set<?> set) {
        StringBuilder sb = new StringBuilder("{");
        set.forEach(item -> sb.append(byteToString(item)).append(", "));
        if (!set.isEmpty()) sb.setLength(sb.length() - 2);
        return sb.append("}").toString();
    }

    private static String formatZSet(ZSetEntry[] zset) {
        StringBuilder sb = new StringBuilder("{");
        for (ZSetEntry entry : zset) {
            sb.append(byteToString(entry.getElement()))
              .append(": ")
              .append(entry.getScore())
              .append(", ");
        }
        if (zset.length > 0) sb.setLength(sb.length() - 2);
        return sb.append("}").toString();
    }

    private static String formatHash(Map<?, ?> map) {
        StringBuilder sb = new StringBuilder("{");
        map.forEach((k, v) -> sb.append(byteToString(k))
                              .append("=")
                              .append(byteToString(v))
                              .append(", "));
        if (!map.isEmpty()) sb.setLength(sb.length() - 2);
        return sb.append("}").toString();
    }
}